#include "draw_utils.h"
#include "camera.h"
#include "application.h"
#include "globals.h"

//-----------------------------------------------------------------------------
TCamera camera;
#include "aic_patrol.h"

#define sign(x) (((x) < 0) ? -1.0f : 1.0f )

aic_patrol e1;
TEntity3D e2;

struct TCameraController3rdPerson {
	TEntity3D *target;
	float      distance_to_target;
	float      yaw, pitch;

	TCameraController3rdPerson( ) 
	: distance_to_target( 10.0f )
	{ }

	void update( TCamera *camera ) {
		D3DXVECTOR3 src = target->getPosition() - distance_to_target * target->getFront();
		src.y = 10.0f;
		camera->lookAt( src, target->getPosition(), D3DXVECTOR3(0,1,0));
	}
};


TCameraController3rdPerson camera_controller;

//-----------------------------------------------------------------------------
void TApplication::onBoot() {
    // Turn off culling, so we see the front and back of the triangle
    Globals::g_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );

    // Turn off D3D lighting, since we are providing our own vertex colors
    Globals::g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE );

	camera.lookAt( D3DXVECTOR3( 6,7,5 )
		         , D3DXVECTOR3( 3,0,0 )
		         , D3DXVECTOR3( 0,1,0 ));
	camera.setProjectionParams( D3DXToRadian( 65.0f ), static_cast<float>(xres) / static_cast<float>(yres), 1.0f, 100.0f );
	e1.Init();
	e1.setPosition( D3DXVECTOR3( 0,0,2 ) );
	e2.setPosition( D3DXVECTOR3( 3,0,0 ) );

	//D3DXMatrixRotationY( &e1.world, D3DXToRadian( 30.0f ) );

	camera_controller.target = &e1;
}


//-----------------------------------------------------------------------------
VOID SetupCameraMatrices()
{
    // For our world matrix, we will just rotate the object about the y-axis.
    D3DXMATRIXA16 matWorld;
	D3DXMatrixIdentity( &matWorld );
	Globals::g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
    Globals::g_pd3dDevice->SetTransform( D3DTS_VIEW, &camera.getView() );
    Globals::g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &camera.getProjection() );
}

//-----------------------------------------------------------------------------
void TApplication::update( float delta ) {
	(void) delta;
	e1.Recalc();
	// Mover la entidad
	float amount_moved = delta * 3.0f;
	float amount_rotated = delta * 3.0f;
	if( isPressed( 'W' ) )
		e1.move( e1.getFront() * amount_moved );
	if( isPressed( 'S' ) )
		e1.move( -e1.getFront() * amount_moved );
	if( isPressed( 'A' ) )
		e1.move( e1.getLeft() * amount_moved );
	if( isPressed( 'D' ) )
		e1.move( -e1.getLeft() * amount_moved );
	if( isPressed( 'Q' ) )
		e1.rotateY( amount_rotated );
	if( isPressed( 'E' ) )
		e1.rotateY( -amount_rotated );
	
	if( isPressed( 'Y' ) ) {
		float angle = e1.getAngleToPoint( e2.getPosition() );
		// amount_rotated is always > 0
		if( amount_rotated > fabsf( angle ) )
			amount_rotated = fabsf( angle );
		e1.rotateY( amount_rotated * sign( angle ) );
	}

	//camera_controller.update( &camera );
}

//-----------------------------------------------------------------------------
void TApplication::render()
{
    // Clear the backbuffer to a black color
    Globals::g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB( 0, 0, 0 ), 1.0f, 0 );

    // Begin the scene
    if( SUCCEEDED( Globals::g_pd3dDevice->BeginScene() ) )
    {
        // Setup the world, view, and projection matrices
        SetupCameraMatrices();
		drawGridXZ( 3, 5 );
		//drawAxis( );

		e1.render();
		float half_fov = D3DXToRadian( 30.0f );
		unsigned color = 0xffffffff;
		if( e1.isInsideVisionCone( e2.getPosition(), half_fov,e1.getPosition(),e1.getZfar() ) )
			color = 0xffffff00;
		drawLocalConeXZ( half_fov, color,e1.getZfar());

		static float time = 0.0f;
		time += 0.016f;
		e2.setPosition( D3DXVECTOR3( 10 + 5 * sin( time ), 0, 0 ) );
		e2.render();

		printf2D( 10, 10, D3DCOLOR_ARGB( 255, 255, 0, 0 ), "time: %f", time );

        // End the scene
        Globals::g_pd3dDevice->EndScene();
    }

    // Present the backbuffer contents to the display
    Globals::g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}






